/*
    实现往通讯录中写入的操作
*/

#include "contacts.pb.h"
#include <fstream>
#include <iostream>
#include <string>
#include <string.h>
using namespace std;

void AddPeopleInfo(contacts1::Contacts *contacts_ptr)
{
    for (int j = 0;; j++)
    {
        std::cout << "--------- 新增联系人(输入“退出”即可结束新增联系人) --------" << std::endl;
        std::cout << " 请输入联系人姓名： ";
        string name;
        getline(std::cin, name);
        if(name=="退出"){
            break;
        }
        contacts1::PeopleInfo *peopleinfo = contacts_ptr->add_people(); //添加一个people消息
        peopleinfo->set_name(name);
        std::cout << " 请输入联系人年龄： ";
        string age;
        getline(std::cin, age);
        peopleinfo->set_age(age);
        for (int i = 0;; i++)
        {
            std::cout << " 请输入联系人电话 " << i + 1 << "(只输入回车完成电话的新增): ";
            string number;
            getline(std::cin, number);
            if (number.empty())
            {
                break;
            }
            contacts1::Phone *phone = peopleinfo->add_phone();  //添加一个phone信息
            phone->set_number(number);
            std::cout<< " 请输入电话类型：(MP/移动电话:0  TEL/固定电话:1): ";
            int type=0;
            std::cin>>type;
            std::cin.ignore(256,'\n');
            switch (type)
            {
            case 0:
                phone->set_type(contacts1::MP);
                break;
            case 1:
                phone->set_type(contacts1::TEL);
                break;
            default:
                std::cout << "⾮法选择，使⽤默认值！" << std::endl;
                break;
            }
        }


        //增加Any类型
        contacts1::Address address;
        std::cout<<" 请输入家庭地址：";
        string home_address;
        getline(std::cin,home_address);
        address.set_home_address(home_address);
        std::cout<<" 请输入单位地址：";
        string unit_address;
        getline(std::cin,unit_address);
        address.set_unit_address(unit_address);
        google::protobuf::Any * data=peopleinfo->mutable_address(); //若该对象存在，则直接返回该对象，若不存在则新new 一个。
        //类型转化：转化为Any类型
        data->PackFrom(address);


        //增加oneof类型
        std::cout<<" 请输入联系人性别：(1.male  2.female)：";
        int male=0;
        std::cin>>male;
        std::cin.ignore(256,'\n');
        if(male==1){
            string male="male";
            peopleinfo->set_male(male);
        }
        else if(male==2){
            string female="female";
            peopleinfo->set_female(female);
        }
        else{
            std::cout<<" 非法选择，设置为默认值！"<<std::endl;
        }
        

        //增加map类型
        for(int i=1;;i++){
            std::cout<<"添加第"<<i<<"条备注的标题：(只输入回车表示添加结束)";
            string remark_key;
            getline(std::cin,remark_key);
            if(remark_key.empty()){
                break;
            }
            std::cout<<"添加第"<<i<<"条备注的内容：";
            string remark_value;
            getline(std::cin,remark_value);
            
            //开辟remarks空间
            google::protobuf::Map<std::string, std::string> *remarks=peopleinfo->mutable_remarks();
            remarks->insert({remark_key,remark_value});
        }
    }
}

int main()
{

    contacts1::Contacts contacts;

    // 读取本地已经存在的联系人文件
    fstream input("contacts.bin", ios::in | ios::binary);

    if (!input)
    {
        std::cout << " contacts.bin not find,create new file! " << std::endl;
    }
    else if (!contacts.ParseFromIstream(&input))
    {
        std::cerr << " Failed to parse contacts.bin " << std::endl;
        input.close();
        return -1;
    }

    AddPeopleInfo(&contacts);

    // 向文件中覆盖写入新的内容
    fstream output("contacts.bin", ios::out | ios::binary | ios::trunc);
    if (!contacts.SerializeToOstream(&output))
    {
        std::cerr << " Failed to serialize ,write error! " << std::endl;
        output.close();
        input.close();
        return -1;
    }

    std::cout << " write success! " << std::endl;
    output.close();
    input.close();
    /*
        在程序结束时调⽤ ShutdownProtobufLibrary()，为了删除 Protocol Buffer 库分配的所
    有全局对象。对于⼤多数程序来说这是不必要的，因为该过程⽆论如何都要退出，并且操作系统将负责
    回收其所有内存。但是，如果你使⽤了内存泄漏检查程序，该程序需要释放每个最后对象，或者你正在
    编写可以由单个进程多次加载和卸载的库，那么你可能希望强制使⽤ Protocol Buffers 来清理所有
    内容。
    */
    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}